<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - watch</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">
	</head>

	<body>
		<div id="container"></div>
		<div id="info">
			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - Rolex + aomap - 610 ko
		</div>

		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js",
					"three/addons/": "./jsm/",
					"tween": "./jsm/libs/tween.module.js"
				}
			}
		</script>

		<script type="module">

			import * as THREE from 'three';
			import * as TWEEN from 'tween';

			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
			import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
			import { HDRLoader } from 'three/addons/loaders/HDRLoader.js';
			import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';

			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

			import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
			import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
			import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
			import { TAARenderPass } from 'three/addons/postprocessing/TAARenderPass.js';

			let composer, camera, scene, renderer;
			let gui, dirLight, pointLight, controls, bloomPass, taaPass;
			let ready = false;

			const meshes = {};
			const materials = {};
			const torad = Math.PI / 180;

			const setting = {
				roughness: 0.09,
				metalness: 1.0,
				opacity: 0.4,
				threshold: 0,
				strength: 0.08,
				radius: 0.0,
				postProcess: false
			};

			init();

			function init() {

				const container = document.getElementById( 'container' );

				camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 20 );
				camera.position.set( 0.8, 0.5, - 1.5 );

				scene = new THREE.Scene();

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.setAnimationLoop( animate );
				renderer.toneMapping = THREE.ACESFilmicToneMapping;
				renderer.toneMappingExposure = 0.7;
				renderer.shadowMap.enabled = true;
				renderer.shadowMap.type = THREE.VSMShadowMap;
				container.appendChild( renderer.domElement );

				new HDRLoader()
					.setPath( 'textures/equirectangular/' )
					.load( 'lobe.hdr', function ( texture ) {

						texture.mapping = THREE.EquirectangularReflectionMapping;
						scene.background = texture;
						scene.environment = texture;
						scene.backgroundBlurriness = 0.5;
						scene.backgroundIntensity = 1.0;
						scene.environmentIntensity = 1.5;

						// model

						const loader = new GLTFLoader().setPath( 'models/gltf/' );
						loader.setDRACOLoader( new DRACOLoader().setDecoderPath( 'jsm/libs/draco/gltf/' ) );
						loader.load( 'rolex.glb', function ( gltf ) {

							gltf.scene.rotation.x = Math.PI * 0.25;

							gltf.scene.traverse( ( child ) => {

								if ( child.isMesh || child.isGroup ) {

									if ( child.isMesh ) {

										child.material.vertexColors = false;
										materials[ child.material.name ] = child.material;
										if ( child.name !== 'glass' ) {

											child.receiveShadow = true;
										    child.castShadow = true;

										}

									}

									meshes[ child.name ] = child;

								}

							} );

							scene.add( gltf.scene );

							meshes.glass.material = new THREE.MeshPhysicalMaterial( {
								color: 0x020205,
								transparent: true, opacity: setting.opacity,
								metalness: 0, roughness: 0,
								iridescence: 0.3,
								clearcoat: 1.0,
								blending: THREE.AdditiveBlending
							} );

							ready = true;

							createGUI();

						} );

					} );



				controls = new OrbitControls( camera, renderer.domElement );
				controls.minDistance = 0.3;
				controls.maxDistance = 10;
				controls.target.set( 0, - 0.1, 0 );
				controls.enableDamping = true;
				controls.dampingFactor = 0.05;
				controls.update();

				dirLight = new THREE.DirectionalLight( 0xFFFFFF, 6 );
				dirLight.position.set( - 0.1, 0.6, 0.4 );
				dirLight.castShadow = true;
				scene.add( dirLight );
				const shadow = dirLight.shadow;
				shadow.mapSize.width = shadow.mapSize.height = 1024;
				shadow.radius = 8;
				shadow.bias = - 0.0005;
				const shadowCam = shadow.camera, s = 0.5;
				shadowCam.near = 0.1;
				shadowCam.far = 2;
				shadowCam.right = shadowCam.top	= s;
				shadowCam.left = shadowCam.bottom = - s;
				// debug shadow
				//scene.add(  new THREE.CameraHelper(shadowCam) );

				pointLight = new THREE.PointLight( 0x7b8cad, 1, 0, 2 );
				pointLight.position.set( 0.3, - 0.2, - 0.2 );
				scene.add( pointLight );

				window.addEventListener( 'resize', onWindowResize );

				moveCamera();

			}

			function moveCamera() {

				controls.enabled = false;
				controls.enableDamping = false;

				const sph = new THREE.Spherical();
				const target = controls.target;
				const tmp = {
				    distance: controls.getDistance(),
				    phi: controls.getPolarAngle(),
				    theta: controls.getAzimuthalAngle()
				};

				new TWEEN.Tween( tmp )
					.to( { distance: 1, theta: - Math.PI * 0.2 }, 6000 )
					.easing( TWEEN.Easing.Quadratic.Out )
					.onUpdate( function ( n ) {

						sph.set( n.distance, n.phi, n.theta );
						camera.position.setFromSpherical( sph ).add( target );
						camera.lookAt( target );

					} )
					.onComplete( function () {

						controls.enabled = true;
						controls.enableDamping = true;

					} )
					.start();

			}

			function postProcess( b ) {

				if ( b ) {

					if ( composer ) return;

					bloomPass = new UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 1.5, 0.4, 0.85 );
					bloomPass.threshold = setting.threshold;
					bloomPass.strength = setting.strength;
					bloomPass.radius = setting.radius;

					taaPass = new TAARenderPass( scene, camera );
					taaPass.sampleLevel = 2;
					taaPass.unbiased = false;

					composer = new EffectComposer( renderer );
					composer.setPixelRatio( window.devicePixelRatio );
					composer.setSize( window.innerWidth, window.innerHeight );

					composer.addPass( taaPass );
					composer.addPass( bloomPass );
					composer.addPass( new OutputPass() );

				} else {

					if ( ! composer ) return;
					composer.dispose();
					composer = null;
					bloomPass = null;
					taaPass = null;

				}

			}

			function createGUI() {

				gui = new GUI();
				gui.add( setting, 'roughness', 0, 1, 0.01 ).onChange( upMaterial );
				gui.add( setting, 'metalness', 0, 1, 0.01 ).onChange( upMaterial );
				gui.add( setting, 'opacity', 0, 1, 0.01 ).onChange( upMaterial );

				//

				gui.add( setting, 'postProcess' ).onChange( postProcess );
				gui.add( setting, 'threshold', 0, 1, 0.01 ).onChange( upBloom );
				gui.add( setting, 'strength', 0, 3, 0.01 ).onChange( upBloom );
				gui.add( setting, 'radius', 0, 1, 0.01 ).onChange( upBloom );

			}

			function upMaterial() {

				materials.Gold.metalness = materials.Silver.metalness = setting.metalness;
				materials.Gold.roughness = materials.Silver.roughness = setting.roughness;
				meshes.glass.material.opacity = setting.opacity;

			}

			function upBloom() {

				if ( ! bloomPass ) return;
				bloomPass.threshold = setting.threshold;
				bloomPass.strength = setting.strength;
				bloomPass.radius = setting.radius;

			}

			function getTime() {

				const currentDate = new Date();
				let hour = currentDate.getHours();
				const minute = currentDate.getMinutes();
				const second = currentDate.getSeconds();
				let day = currentDate.getDay();
				const month = currentDate.getMonth();
				const milli = currentDate.getMilliseconds();
				if ( hour >= 12 ) hour -= 12;
				if ( day > 30 ) day = 30;

				meshes.hour.rotation.y = - hour * 30 * torad;
				meshes.minute.rotation.y = - minute * 6 * torad;
				meshes.second.rotation.y = - second * 6 * torad;
				meshes.mini_03.rotation.y = - day * 12 * torad;
				meshes.mini_02.rotation.y = - month * 30 * torad;
				meshes.mini_01.rotation.y = - milli * 0.36 * torad;

			}

			function onWindowResize() {

				const width = window.innerWidth;
				const height = window.innerHeight;

				camera.aspect = width / height;
				camera.updateProjectionMatrix();
				renderer.setSize( width, height );
				if ( composer ) {

					composer.setSize( width, height );

				}

			}

			//

			function animate() {

				controls.update();

				TWEEN.update();

				if ( composer ) composer.render();
				else renderer.render( scene, camera );

				if ( ready ) getTime();

			}

		</script>

	</body>
</html>
